package com.jeecg.p3.system.interceptors;

import com.jeecg.p3.core.annotation.SkipAuth;
import com.jeecg.p3.core.enums.SkipPerm;
import com.jeecg.p3.dict.entity.ProjectErrorConfig;
import com.jeecg.p3.system.def.SystemProperties;
import org.jeecgframework.p3.core.common.utils.DataDictTool;
import org.jeecgframework.p3.core.common.utils.StringUtil;
import org.jeecgframework.p3.core.util.SignatureUtil;
import org.jeecgframework.p3.core.util.oConvertUtils;
import org.jeecgframework.p3.core.utils.common.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 签名器 - H5网页访问
 *
 * @author zhoujf
 */
@Component
public class AccessSignInterceptor implements HandlerInterceptor {
    private final static Logger logger = LoggerFactory.getLogger(AccessSignInterceptor.class);
    private static final String SIGN_PARAM_NAME = "sign";
    private static final String SESSION_OPENID = "openid";
    private static final String SESSION_NICKNAME = "nickname";

    /**
     * 活动访问签名拦截，防止串改数据
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        // 注解排除权限拦截机制
        if (this.skipPermission(object)) {
            return true;
        }
        // 用户访问的资源地址
        String requestPath = getRequestPath(request);
        //第三方公众平台检验文件
        if (StringUtils.isNotBlank(requestPath) && requestPath.equalsIgnoreCase("4453438762.txt")) {
            return true;
        } else if (StringUtils.isNotBlank(requestPath) && requestPath.equalsIgnoreCase("MP_verify_2u9LGKjzRvt0aawL.txt")) {
            return true;
        }else if (StringUtils.isNotBlank(requestPath) && requestPath.equalsIgnoreCase("MP_verify_xgLK7iUrOWODWNjw.txt")){
            return true;
        }
        String requestUrl = getRequestUrl(request);
        logger.debug("-------------requestUrl-------------" + requestUrl);
        String basePath = request.getContextPath();
        request.setAttribute("basePath", basePath);
        if (oConvertUtils.isNotEmpty(requestPath)) {
            if (requestPath.indexOf("/back/") > -1) {
                return true;
            } else if (requestUrl.indexOf(SIGN_PARAM_NAME + "=") != -1) {
                String openid = request.getParameter("openid");
                String nickname = request.getParameter("nickname");
                String sign = request.getParameter(SIGN_PARAM_NAME);
                logger.debug(
                        "----openid--------" + openid + "----nickname--------" + nickname + "----Sign--------" + sign);
                if (StringUtil.notEmpty(sign)) {
                    Map<String, String> paramMap = getSignMap(request);
                    boolean check = SignatureUtil.checkSign(paramMap, SystemProperties.SIGN_KEY, sign);
                    logger.debug("--------------SignatureUtil.checkSign---------check--" + check);
                    if (check) {
                        if (StringUtil.isEmpty(openid)) {
                            logger.info("---------------SignInterceptor--------------openid为空");
                            return false;
                        }
                        request.getSession().setAttribute(SESSION_OPENID, openid);
                        request.getSession().setAttribute(SESSION_NICKNAME, nickname);
                        response.sendRedirect(getRedirectUrl(basePath + "/" + requestPath, paramMap));
                        logger.info("---------------SignInterceptor--------------签名验证失败");
                        return false;
                    }
                }
            } else {
                String session_openid = (String) request.getSession().getAttribute(SESSION_OPENID);
                logger.debug("----------session_openid------------------------" + session_openid);
                if (StringUtil.notEmpty(session_openid)) {
                    String openid = request.getParameter("openid");
                    if (StringUtil.notEmpty(openid)) {
                        if (session_openid.equals(openid)) {
                            return true;
                        }
                    } else {
                        return true;
                    }
                }
            }
            String defaultUrl = basePath + "/system/noAuth.do";
            logger.info("---------------SignInterceptor--------------没有权限---requestPath=" + requestPath);
            redirectUrl404(requestPath, defaultUrl, response);
            return false;
        } else {
            return true;
        }
    }

    /**
     * 是否排除拦截
     *
     * @param handler
     * @return
     */
    private boolean skipPermission(Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            SkipAuth jauthType = handlerMethod.getBean().getClass().getAnnotation(SkipAuth.class);
            if (jauthType != null && (jauthType.auth() == SkipPerm.SKIP_ALL || jauthType.auth() == SkipPerm.SKIP_SIGN)) {
                return true;
            } else {
                SkipAuth jauthMethod = handlerMethod.getMethod().getAnnotation(SkipAuth.class);
                if (jauthMethod != null && (jauthMethod.auth() == SkipPerm.SKIP_ALL || jauthMethod.auth() == SkipPerm.SKIP_SIGN)) {
                    return true;
                }
            }
        }
        return false;
    }

    private Map<String, String> getSignMap(HttpServletRequest request) {
        Map<String, String> paramMap = new HashMap<String, String>();
        Map<String, String[]> map = request.getParameterMap();
        Set<Entry<String, String[]>> es = map.entrySet();
        Iterator<Entry<String, String[]>> it = es.iterator();
        while (it.hasNext()) {
            @SuppressWarnings("rawtypes")
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object ov = entry.getValue();
            String v = "";
            if (ov instanceof String[]) {
                String[] value = (String[]) ov;
                v = value[0];
            } else {
                v = ov.toString();
            }
            paramMap.put(k, v);
        }
        return paramMap;
    }

    private String getRedirectUrl(String requestPath, Map<String, String> paramMap) {
        Set<Entry<String, String>> es = paramMap.entrySet();
        Iterator<Entry<String, String>> it = es.iterator();
        StringBuffer sb = new StringBuffer();
        sb.append(requestPath + "?");
        while (it.hasNext()) {
            @SuppressWarnings("rawtypes")
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"null".equals(v) && !"sign".equals(k) && !"nickname".equals(k)
                    && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        String redirectUrl = sb.toString();
        redirectUrl = redirectUrl.substring(0, redirectUrl.length() - 1);
        logger.info("---------------redirectUrl--------------" + redirectUrl);
        return redirectUrl;
    }

    /**
     * 获得请求路径
     *
     * @param request
     * @return
     */
    private String getRequestPath(HttpServletRequest request) {
        String requestPath = request.getRequestURI();
        requestPath = requestPath.substring(request.getContextPath().length() + 1);// 去掉项目路径
        return requestPath;
    }

    private String getRequestUrl(HttpServletRequest request) {
        String param = request.getQueryString();
        String requestUrl = request.getRequestURI();
        if (param != null) {
            requestUrl = requestUrl + "?" + request.getQueryString();
        }
        if (requestUrl.indexOf("#") != -1) {
            requestUrl = requestUrl.substring(0, requestUrl.indexOf("#"));
        }
        return requestUrl;
    }

    private String getProjectPath(String requestPath) {
        String projectPath = "";
        if (StringUtils.isNotEmpty(requestPath)) {
            requestPath.replace("\\", "/");
            int index = requestPath.lastIndexOf("/");
            if (index != -1) {
                projectPath = requestPath.substring(0, index);
                logger.info("---------------projectPath--------------" + projectPath);
            }
        }
        return projectPath;
    }

    private void redirectUrl404(String requestPath, String defaultUrl, HttpServletResponse response)
            throws IOException {
        String projectPath = getProjectPath(requestPath);
        try {
            if (StringUtils.isNotEmpty(projectPath)) {
                // 根据projectPath查询对应的404页面
                DataDictTool tool = new DataDictTool();
                ProjectErrorConfig config = tool.getSysErrorConfig(projectPath);
                String url = defaultUrl;
                if (config != null) {
                    if (StringUtils.isNotEmpty(config.getRedirectUrl())) {
                        url = config.getRedirectUrl();
                    }
                }
                logger.info("---------------redirectUrl404--------------" + url);
                response.sendRedirect(url);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("---------------redirectUrl404----异常----------" + defaultUrl);
            response.sendRedirect(defaultUrl);
        }
    }
}
